package org.jeecg.activiti.controller;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.InclusiveGateway;
import org.activiti.bpmn.model.ParallelGateway;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.task.Task;
import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.activiti.entity.ActHiModelFormData;
import org.jeecg.activiti.entity.ActKAppendFormData;
import org.jeecg.activiti.entity.ActKAppendFormDeployment;
import org.jeecg.activiti.entity.ActKHandleResult;
import org.jeecg.activiti.entity.ActKNode;
import org.jeecg.activiti.entity.ActKNodeDesign;
import org.jeecg.activiti.entity.ActKNodeFile;
import org.jeecg.activiti.entity.ActReModelExtend;
import org.jeecg.activiti.entity.ActReModelFormData;
import org.jeecg.activiti.entity.ActivitiConstant;
import org.jeecg.activiti.entity.HistoricTaskVo;
import org.jeecg.activiti.service.IActHiModelFormDataService;
import org.jeecg.activiti.service.IActKAppendFormDataService;
import org.jeecg.activiti.service.IActKAppendFormDeploymentService;
import org.jeecg.activiti.service.IActKHandleResultService;
import org.jeecg.activiti.service.IActKNodeDesignService;
import org.jeecg.activiti.service.IActKNodeFileService;
import org.jeecg.activiti.service.IActKNodeService;
import org.jeecg.activiti.service.IActReModelExtendService;
import org.jeecg.activiti.service.IActReModelFormDataService;
import org.jeecg.activiti.util.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.modules.online.cgform.entity.OnlCgformHead;
import org.jeecg.modules.online.cgform.service.IOnlCgformFieldService;
import org.jeecg.modules.online.cgform.service.IOnlCgformHeadService;
import org.jeecg.modules.online.cgform.util.SqlSymbolUtil;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.api.client.util.ArrayMap;
import com.googlecode.aviator.AviatorEvaluator;

import cn.hutool.db.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;

/**
 * 流程历史管理
 */
@Slf4j
@RestController
@RequestMapping("/activiti/history")
@Api(tags = "流程历史数据管理")
public class ActivitiHistoryController {

    @Autowired
    private HistoryService historyService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private IActKNodeService iActKNodeService;

    @Autowired
    private ISysUserService iSysUserService;

    @Autowired
    private IActKHandleResultService iActKHandleResultService;

    @Autowired
    private IActKAppendFormDataService iActKAppendFormDataService;

    @Autowired
    private IActKAppendFormDeploymentService iActKAppendFormDeploymentService;

    @Autowired
    private IActKNodeFileService iActKNodeFileService;
    
    @Autowired
    private IActKNodeDesignService actKNodeDesignService;

    @Autowired
    private IActHiModelFormDataService iActHiModelFormDataService;
    
    @Autowired
    private IActReModelExtendService actReModelExtendService;
    
    @Autowired
    private IOnlCgformHeadService onlCgformHeadService;
    
    @Autowired
    private IOnlCgformFieldService fieldService;
    
    @Autowired
    private IActReModelFormDataService iActReModelFormDataService;

    private static List<HistoricActivityInstance> tempList = null;

    private static BpmnModel bpmnModel = null;

    private static List<HistoricActivityInstance> activityFinishedList = null;

	@ApiOperation(value="流程-流程流转历史", notes="流程流转历史")
    @RequestMapping(value = "/historicFlow", method = RequestMethod.GET)
    public Result<Object> historicFlow(@ApiParam(value="processInstanceId" ,name="流程实例Id") @RequestParam String processInstanceId,
    		@ApiParam(value="taskId" ,name="任务Id") @RequestParam(required = false,defaultValue = "") String taskId){
        List<HistoricTaskVo> list = new ArrayList<>();
        List<HistoricTaskInstance> taskList = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId).orderByHistoricTaskInstanceStartTime().desc().list();
        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
        
        boolean isShowAppendForm = false;
        if (historicTaskInstance != null) {
        	ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(historicTaskInstance.getProcessDefinitionId()).singleResult();
            Model model = repositoryService.createModelQuery().modelKey(processDefinition.getKey()).singleResult();
            ActKNodeDesign actKNode = actKNodeDesignService.getOne(new QueryWrapper<ActKNodeDesign>()
                    .eq("node_id", historicTaskInstance.getTaskDefinitionKey())
                    .eq("model_id", model.getId()));
            if(actKNode != null && actKNode.getIsShowAppendForm()){
            	isShowAppendForm = actKNode.getIsShowAppendForm();
            }
        }
        for(HistoricTaskInstance e : taskList){
            HistoricTaskVo htv = new HistoricTaskVo(e);

            // 处理审批意见
            ActKHandleResult actKHandleResult = iActKHandleResultService.getOne(new QueryWrapper<ActKHandleResult>()
                    .eq("node_id", e.getTaskDefinitionKey())
                    .eq("process_instance_id", processInstanceId)
                    .eq("task_id", htv.getId())
                    .eq("execution_id", htv.getExecutionId()));
            if (actKHandleResult != null) {
                htv.setComment(actKHandleResult.getComment());
                htv.setFlagTxt(actKHandleResult.getResult());
            }
            if(isShowAppendForm){
            	// 查询附加表单数据
                ActKAppendFormDeployment actKAppendForm = iActKAppendFormDeploymentService.getOne(new QueryWrapper<ActKAppendFormDeployment>()
                        .eq("node_id", e.getTaskDefinitionKey()).eq("process_definition_id", e.getProcessDefinitionId()));
                
                // 如果该节点存在附加表单
                if (actKAppendForm != null) {
                    ActKAppendFormData actKAppendFormData = iActKAppendFormDataService.getOne(new QueryWrapper<ActKAppendFormData>()
                            .eq("node_id", e.getTaskDefinitionKey())
                            .eq("process_instance_id", processInstanceId)
                            .eq("task_id", htv.getId())
                            .eq("execution_id", htv.getExecutionId()));

                    htv.setActKAppendForm(actKAppendForm);
                    htv.setActKAppendFormData(actKAppendFormData);
                }
            }

            // 查询上传的附件
            List<ActKNodeFile> actKNodeFiles = iActKNodeFileService.list(new QueryWrapper<ActKNodeFile>()
                    .eq("node_id", e.getTaskDefinitionKey())
                    .eq("process_instance_id", processInstanceId)
                    .eq("task_id", htv.getId())
                    .eq("execution_id", htv.getExecutionId()));
            if (CollectionUtils.isNotEmpty(actKNodeFiles)) {
                htv.setActKNodeFiles(actKNodeFiles);
            }

            // 获取节点出去的线
            String nodeId = e.getTaskDefinitionKey();
            ActKNode actKNode = iActKNodeService.getOne(new QueryWrapper<ActKNode>()
                    .eq("node_id", nodeId).eq("process_definition_id", e.getProcessDefinitionId()));
            htv.setOutgoing(actKNode.getOutgoing());
            try{
            	htv.setAssignee(iSysUserService.getUserByName(htv.getAssignee()).getRealname());
            }catch (Exception ex) {
            	ex.printStackTrace();
			}

            list.add(htv);
        }

        return Result.OK(list);
    }

    /**
     * 已办列表
     * */
    @ApiOperation(value="流程-已办列表", notes="已办列表")
    @RequestMapping(value = "/doneList" ,method = RequestMethod.GET)
    public Result<Object> doneList(String modelKey, String modelName, String id,
			   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
			   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize){
        Map<String, Object> result = new ArrayMap<>();

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        Page page = new Page(pageNo,pageSize);
        List<HistoricTaskInstance> taskList  = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee(sysUser.getUsername())
                .finished()
                .orderByHistoricTaskInstanceEndTime().desc()
                .listPage(page.getStartPosition(),pageSize);
        long total = historyService.createHistoricTaskInstanceQuery()
	        .taskAssignee(sysUser.getUsername())
	        .finished()
	        .orderByHistoricTaskInstanceEndTime().desc()
	        .count();

        List<Map<String,Object>> leaveTasks = new ArrayList<>();

        for (HistoricTaskInstance task : taskList) {
        	if(org.apache.commons.lang3.StringUtils.isNotEmpty(id) && !task.getId().equals(id)){
        		continue;
        	}
            Map<String,Object> leaveTask = new HashMap<>();
            ActHiModelFormData actHiModelFormData = iActHiModelFormDataService.getOne(new QueryWrapper<ActHiModelFormData>()
                    .eq("process_instance_id", task.getProcessInstanceId()));
            if (actHiModelFormData != null) {
                Model model = repositoryService.createModelQuery().modelId(actHiModelFormData.getModelId()).singleResult();

                if (org.springframework.util.StringUtils.isEmpty(modelKey)
                        && org.springframework.util.StringUtils.isEmpty(modelName)) {
                    handelHistoryTask(leaveTask, model, actHiModelFormData, task);
                    leaveTasks.add(leaveTask);
                } else if (!org.springframework.util.StringUtils.isEmpty(modelKey)
                        && org.springframework.util.StringUtils.isEmpty(modelName) && model.getKey().contains(modelKey)) {
                    handelHistoryTask(leaveTask, model, actHiModelFormData, task);
                    leaveTasks.add(leaveTask);
                } else if (org.springframework.util.StringUtils.isEmpty(modelKey)
                        && !org.springframework.util.StringUtils.isEmpty(modelName) && model.getName().contains(modelName)) {
                    handelHistoryTask(leaveTask, model, actHiModelFormData, task);
                    leaveTasks.add(leaveTask);
                } else if (!org.springframework.util.StringUtils.isEmpty(modelKey)
                        && !org.springframework.util.StringUtils.isEmpty(modelName)
                        && model.getKey().contains(modelKey)
                        && model.getName().contains(modelName)) {
                    handelHistoryTask(leaveTask, model, actHiModelFormData, task);
                    leaveTasks.add(leaveTask);
                }
            }
        }

        result.put("records",leaveTasks);
        result.put("total", total);
        return Result.OK(result);
    }

    /**
     * 封装历史任务
     * @param leaveTask
     * @param model
     * @param actHiModelFormData
     * @param task
     */
    private void handelHistoryTask(Map<String,Object> leaveTask, Model model, ActHiModelFormData actHiModelFormData, HistoricTaskInstance task){
    	ActReModelFormData actReModelFormData = iActReModelFormDataService.getOne(new QueryWrapper<ActReModelFormData>().eq("process_instance_id", task.getProcessInstanceId()));
        leaveTask.put("modelName", model.getName());
        leaveTask.put("modelKey", model.getKey());
        leaveTask.put("id", task.getId());
        leaveTask.put("name", task.getName());
        leaveTask.put("creator", task.getOwner());
        leaveTask.put("createTime", task.getCreateTime());
        leaveTask.put("formDataId", actHiModelFormData.getId());
        leaveTask.put("modelId", actHiModelFormData.getModelId());
        leaveTask.put("startTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(task.getStartTime()));
        leaveTask.put("endTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(task.getEndTime()));
        leaveTask.put("totalTime", StringUtils.getTimeDiff(task.getStartTime(), task.getEndTime()));
        leaveTask.put("processDefinitionId", task.getProcessDefinitionId());
        leaveTask.put("processInstanceId", task.getProcessInstanceId());
        
        leaveTask.put("formData", actHiModelFormData.getFormData());
        leaveTask.put("tableId", actHiModelFormData.getTableId());
        leaveTask.put("tableName", actHiModelFormData.getTableName());
        // 查询表单数据ID
        SysUser sysUser = iSysUserService.getUserByName(actHiModelFormData.getCreateBy());
        leaveTask.put("instanceName", getInstanceName(actReModelFormData));
        leaveTask.put("processApplyUserName", sysUser.getRealname());
    }
    
    // 获取业务标题
    private String getInstanceName(ActReModelFormData actReModelFormData){
    	if(actReModelFormData == null){
    		return "无业务标题";
    	}
    	ActReModelExtend modelExtend = actReModelExtendService.getOne(new QueryWrapper<ActReModelExtend>().eq("model_id", actReModelFormData.getModelId()));
    	Map<String, Object> variables;
        if(actReModelFormData.getTableId() == null){
    		variables = JSONObject.toJavaObject(JSONObject.parseObject(actReModelFormData.getFormData()), Map.class);
        }else{
        	OnlCgformHead head = onlCgformHeadService.getById(actReModelFormData.getTableId());
         	variables = this.fieldService.queryBpmData(actReModelFormData.getTableId(), head.getTableName(), actReModelFormData.getDataId());
         	variables = SqlSymbolUtil.getValueType(variables);
        }
        String expression = modelExtend.getTitle();
        if(org.apache.commons.lang3.StringUtils.isEmpty(expression)){
        	return "无业务标题";
        }
        String title;
        try{
        	title = AviatorEvaluator.execute(expression,variables)+"";
        }catch(Exception e) {
        	log.error("expression========>"+expression);
        	title = "标题加载失败";
        }
        return title;
    }

    @GetMapping("/getHistoryNode")
    @ApiOperation(value = "获取流程实例已执行节点", notes = "获取流程实例已执行节点")
    public Result<List<Map<String,Object>>> getHistoryNode(@ApiParam("流程实例id") @RequestParam String procInstId,
                                                           @ApiParam("任务id") @RequestParam String taskId) {
        Result<List<Map<String,Object>>> result = new Result<>();

        tempList = new ArrayList<>();

        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if(task != null){
        	String currActivityId = task.getTaskDefinitionKey();

            // 添加发起人任务节点
            List<Map<String,Object>> resultList = new ArrayList<>();
            Map<String, Object> tempMap = new HashMap<>();
            tempMap.put("nodeName", ActivitiConstant.PROCESS_CREATOR_NAME);
            tempMap.put("nodeId", ActivitiConstant.PROCESS_CREATOR_KEY);
            resultList.add(tempMap);

            activityFinishedList = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(procInstId)
                    .activityType("userTask")
                    .finished()
                    .orderByHistoricActivityInstanceEndTime()
                    .desc()
                    .list();

            bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());

            getReverseNodeList(currActivityId);

            for (HistoricActivityInstance historicActivityInstance : tempList) {
                tempMap = new HashMap<>();
                tempMap.put("nodeName", historicActivityInstance.getActivityName());
                tempMap.put("nodeId", historicActivityInstance.getActivityId());
                if (!resultList.contains(tempMap)) {
                    resultList.add(tempMap);
                }
            }
            result.setResult(resultList);
        }
        
        return result;
    }

    /**
     * 逆向获取执行过的任务节点：
     * 1、子流程只能获取到本子流程节点+主流程节点，不能获取兄弟流程任务节点；
     * 2、主流程任务节点不能获取子流程任务节点；
     * @param currActivityId
     */
    private void getReverseNodeList(String currActivityId) {
        // 获取当前节点的进线，通过进线查询上个节点
        FlowNode currFlow = (FlowNode)bpmnModel.getMainProcess().getFlowElement(currActivityId);
        List<SequenceFlow> incomingFlows = currFlow.getIncomingFlows();

        // 找到上个任务节点
        for (SequenceFlow incomingFlow : incomingFlows) {
            String sourceNodeId = incomingFlow.getSourceRef();
            FlowNode sourceFlowNode = (FlowNode)bpmnModel.getMainProcess().getFlowElement(sourceNodeId);
            String gatewayType = sourceNodeId.substring(sourceNodeId
                    .lastIndexOf("_") + 1);
            if ((sourceFlowNode instanceof ParallelGateway || sourceFlowNode instanceof InclusiveGateway) && "END".equals(gatewayType.toUpperCase())) {
                sourceNodeId = sourceNodeId.substring(0, sourceNodeId
                        .lastIndexOf("_")) + "_start";
                getReverseNodeList(sourceNodeId);
            } else {
                HistoricActivityInstance tempActivityInstance = null;
                for (HistoricActivityInstance historicActivityInstance : activityFinishedList) {
                    if (historicActivityInstance.getActivityId().equals(sourceNodeId)) {
                        tempActivityInstance = historicActivityInstance;
                        break;
                    }
                }

                // 解决画回头线出现死循环的问题
                if (tempList.contains(tempActivityInstance)) {
                    continue;
                } else {
                    if (tempActivityInstance != null) {
                        tempList.add(tempActivityInstance);
                    }

                    getReverseNodeList(sourceNodeId);
                }
            }
        }
    }
}
